#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import json
import os
import socket

from common.exception.common_exception import ErrCodeException

from ndmp.comm.log import log
from ndmp.comm.const import NDMPCode, Constant
from ndmp.schemas.ndmp_schemas import PermissionInfo, Resource, ListAppV2Response
from ndmp.service.ndmp_service_base import NDMPServiceBase
from ndmp.service.resource.parse_resource_param import ResourceParam
from ndmp.service.client.ndmp_client import AuthConfig


class NDMPResouceService(NDMPServiceBase):
    def __init__(self, req_id: str, job_id: str, sub_id: str):
        super().__init__(req_id, job_id, sub_id)
        self.param = ResourceParam(self.req_id)
    
    def is_ip_reachable(self, ip, port):
        try:
            # 创建一个TCP/IP socket
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            # 设置超时时间为10秒
            sock.settimeout(Constant.TIMOUT)
            # 尝试连接到IP地址和端口
            result = sock.connect_ex((ip, port))
            # 如果连接成功，返回True，否则返回False
            sock.close()
            return result == 0
        except Exception as e:
            sock.close()
            log.error(f"cannot access target ip, {e}")
            return False

    def check_application_server(self):
        """
        功能描述：检查NDMP客户端与服务端的连通性并鉴权
        该接口接受的参数不包含远端用户信息，且本端用户名和密码位于远端相应字段
        """
        log.info(f"Enter check_application_server, req:{self.req_id}.")
        s_key, s_pwd, s_ip = self.param.get_dst_auth(), self.param.get_dst_pwd(), self.param.get_src_ip()
        dst_port = self.param.get_dst_port()
        self.req_opt_ip_rule(s_ip, "add")
        log.info(f" {s_key}, s_ip, {s_ip}, dst_port, {dst_port}")
        if not self.is_ip_reachable(s_ip, dst_port):
            self.report_err_result(NDMPCode.FAILED.value, -2, "ip cannot access!")
        else:
            auth_conf = AuthConfig(s_key, s_pwd, s_ip, dst_port)
            log.info(f" {auth_conf.s_port}, {auth_conf.r_port}")
            err_code, ret, msg = self.authentication(auth_conf)
            self.param.clear()
            msg_result = {
                "type": ret,
                "msg": msg
            }
            log.info(f"Exit check_application_server, message: {msg_result}.")
            self.report_err_result(err_code, ret, json.dumps(msg_result, ensure_ascii=False))
            self.req_opt_ip_rule(s_ip, "del")

    def check_application(self):
        """
        功能描述：检查NDMP客户端与服务端的连通性并鉴权
        """
        log.info(f"Enter check_application, req:{self.req_id}.")
        # 检查PM是否打开NDMP服务开关，未开启直接返回失败，待申请错误码，已开启说明本端用户鉴权成功
        if self.param.get_server_gap() != "1":
            self.report_err_result(NDMPCode.FAILED.value, 0, "NDMP service is not enabled!")
            return
        r_key, r_pwd, r_ip = self.param.get_dst_auth(), self.param.get_dst_pwd(), self.param.get_dst_ip()
        auth_conf = AuthConfig(r_key, r_pwd, r_ip)
        self.req_opt_ip_rule(r_ip, "add")
        err_code, body_err_code, msg = self.authentication(auth_conf)
        self.param.clear()
        log.info(f"Exit check_application, message: {msg}.")
        self.report_err_result(err_code, body_err_code, msg)
        self.req_opt_ip_rule(r_ip, "del")

    def list_application_resource_v2(self):
        """
        功能描述：资源浏览，查询NDMP服务端下的文件系统，并将信息写入结果文件中
        """
        log.info(f"Enter list_application_resource, req:{self.req_id}.")
        try:
            s_key, s_pwd, s_ip = self.param.get_dst_auth(), self.param.get_dst_pwd(), self.param.get_dst_ip()
            dst_port = self.param.get_dst_port()
            log.info(f's_key, {s_key}, s_ip, {s_ip}')
            self.req_opt_ip_rule(s_ip, "add")
            auth_conf = AuthConfig(s_key, s_pwd, s_ip, dst_port)
            err_code, body_err_code, msg = self.authentication(auth_conf)
            if err_code == NDMPCode.FAILED.value:  # 连通性检查失败或者鉴权失败
                # 异常处理，这里是否需要写结果文件
                self.report_err_result(err_code, body_err_code, msg)
                log.error("Authentication failed!")
                return
            count, fs_infos = self.ndmp_client.get_resource()
        except ErrCodeException as err:
            log.error(f"get_resource exception, code: {err.error_code}, mesg: {str(err)}.")
            exception_dict = {"code": err.error_code, "message": str(err)}
            self.report_err_result(NDMPCode.FAILED.value, err.error_code, str(err), exception_dict)
        else:
            response = ListAppV2Response()
            response.total = count
            response.resource_list = fs_infos
            self.report_result(response.dict(by_alias=True))
        finally:
            self.param.clear()
            self.req_opt_ip_rule(s_ip, "del")

    def query_job_permission(self):
        output = PermissionInfo(user="root", group="ndmp", fileMode="0770")
        self.report_result(output.dict(by_alias=True))
